package com.sky.common.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 日期工具类
 */

public class DateUtils {


    /**
     * 日期格式
     */
    public static final String DATE = "yyyy-MM-dd";

    /**
     * 24小时格式
     */
    public static final String DATE_TIME_24 = "yyyy-MM-dd HH:mm:ss";


    /**
     * 毫秒短格式
     */
    public static final String DATE_MILLES_COMPACT = "yyyyMMddHHmmssSSS";

    /**
     * 12小时格式
     */
    public static final String DATE_TIME_12 = "yyyy-MM-dd hh-mm-ss";

    /**
     * 日期短格式
     */
    private static final String DATE_COMPACT = "yyyyMMdd";


    /**
     * 锁对象
     */
    private static final Object LOCK_OBJ = new Object();

    /**
     * 存放不同的日期模板格式的sdf的Map
     */
    private static final Map<String, ThreadLocal<SimpleDateFormat>> sdfMap = new HashMap<>();

    /**
     * 返回一个ThreadLocal的sdf,每个线程只会new一次sdf
     *
     * @param pattern 日期格式
     * @return SimpleDateFormat
     */
    private static SimpleDateFormat getSdf(final String pattern) {
        ThreadLocal<SimpleDateFormat> tl = sdfMap.get(pattern);
        // 此处的双重判断和同步是为了防止sdfMap这个单例被多次put重复的sdf
        if (tl == null) {
            synchronized (LOCK_OBJ) {
                tl = sdfMap.get(pattern);
                if (tl == null) {
                    // 这里是关键,使用ThreadLocal<SimpleDateFormat>替代原来直接new SimpleDateFormat
                    tl = new ThreadLocal<>() {
                        @Override
                        protected SimpleDateFormat initialValue() {
                            return new SimpleDateFormat(pattern);
                        }
                    };
                    sdfMap.put(pattern, tl);
                }
            }
        }
        return tl.get();
    }

    /**
     * 格式化日期。
     *
     * @param date    日期
     * @param pattern 日期格式
     * @return 指定格式的日期字符串
     */
    public static String format(Date date, String pattern) {
        return getSdf(pattern).format(date);
    }

    /**
     * 解析日期字符串
     *
     * @param dateStr 日期字符串
     * @param pattern 日期格式
     * @return 日期对象
     * @throws ParseException 解析异常
     */
    public static Date parse(String dateStr, String pattern) throws ParseException {
        return getSdf(pattern).parse(dateStr);
    }

    /**
     * 解析日期字符串
     * @param dateStr 日期字符串
     * @param pattern 格式
     * @return 日期
     */
    public static Date parseElseNull(String dateStr, String pattern)  {
        if(dateStr!=null && dateStr.length()>0){
            try {
                return getSdf(pattern).parse(dateStr);
            }catch (ParseException e){
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 转换为24小时的格式
     * @param date 日期
     * @return 24小时格式
     */
    public static String time24(Date date) {
        if (date == null) {
            return "";
        }
        return format(date, DATE_TIME_24);
    }

    /**
     * 计算2个日期相差多少秒
     * @param date1 日期1
     * @param date2 日期2
     * @return 相差秒数
     */
    public static long secondPlus(Date date1, Date date2) {
        return Math.abs(date1.getTime() - date2.getTime()) / 1000;
    }

    /**
     * 把日期转换为本地日期
     * @param date 日期
     * @return 本地日期
     */
    public static LocalDate toLocalDate(Date date) {
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        // atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
        return instant.atZone(zoneId).toLocalDate();
    }

    /**
     * 把日期转换为本地日期时间
     * @param date 日期
     * @return 本地日期时间
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        // atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
        return instant.atZone(zoneId).toLocalDateTime();
    }

    /**
     * 把本地日期时间转换为日期
     * @param localDateTime 本地日期时间
     * @return 日期
     */
    public static Date from(LocalDateTime localDateTime){
        return Date.from( localDateTime.atZone( ZoneId.systemDefault()).toInstant());
    }

    /**
     * 把本地日期转换为日期
     * @param localDate 本地日期
     * @return 本地日期时间
     */
    public static Date from(LocalDate localDate){
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * 比较2个日期是否同一天
     * @param date1 日期1
     * @param date2 日期2
     * @return 是否同一天
     */
    public static boolean equalsDay(Date date1, Date date2){
        return toLocalDate(date1).equals(toLocalDate(date2));
    }

    /**
     * 计算第2个日期比第1个日期快几天
     * @param date1 日期1
     * @param date2 日期2
     * @return 天数
     */
    public static int getDayPlus(Date date1, Date date2){
        LocalDate localDate1 =toLocalDate(date1);
        LocalDate localDate2 = toLocalDate(date2);
        Period period = Period.between(localDate1,localDate2);
        return period.getDays();
    }

    /**
     * 计算第2个localDateTime比第1个差多少秒
     * @param localDateTime1 第1个localDateTime
     * @param localDateTime2 第2个localDateTime
     * @return 时间差
     */
    public static int getSecondPlus(LocalDateTime localDateTime1,LocalDateTime localDateTime2){
        long  epochSecond1 = localDateTime1.atZone(ZoneOffset.systemDefault()).toEpochSecond();
        long  epochSecond2 = localDateTime2.atZone(ZoneOffset.systemDefault()).toEpochSecond();
        return (int) (epochSecond2-epochSecond1);
    }

}
